home *** CD-ROM | disk | FTP | other *** search
- /*
- File: DumpARPCache.c
-
- Contains: Dumps the system ARP cache to stdout.
-
- Written by: Quinn "The Eskimo!"
-
- Copyright: Copyright © 1997-1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 7/22/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
-
-
- */
-
- #define qDebug 1
-
- /////////////////////////////////////////////////////////////////////
- // Pick up the standard C stuff.
-
- #include <stdio.h>
- #include <string.h>
-
- /////////////////////////////////////////////////////////////////////
- // Pick up standard OT APIs.
-
- #include <OpenTptInternet.h>
-
- /////////////////////////////////////////////////////////////////////
- // Pick up low-level OT APIs.
-
- #include <OpenTptClient.h>
- #include <OTDebug.h>
-
- /////////////////////////////////////////////////////////////////////
- // Pick up the symbolic name of the various OT modules.
-
- #include <modnames.h>
-
- /////////////////////////////////////////////////////////////////////
- // OTDebugStr is not defined in any OT header files, but it is
- // exported by the libraries, so we define the prototype here.
-
- extern pascal void OTDebugStr(const char* str);
-
- /////////////////////////////////////////////////////////////////////
- // The following equates are actually exported by <miioccom.h>, but
- // they commented out for some reason )-:
-
- // #include <miioccom.h>
-
- #define MIOC_ND 'c' /* ioctl's for Mentat's nd device */
-
- // The following equates define the two "Name Dispatch" ioctls
- // for setting and getting OT internal parameters.
-
- #define ND_GET MIOC_CMD(MIOC_ND, 0) /* Get a value */
- #define ND_SET MIOC_CMD(MIOC_ND, 1) /* Set a value */
-
- /////////////////////////////////////////////////////////////////////
- // The name of the Name Dispatch variables we display.
-
- #define ARP_ND_CACHE_REPORT "arp_cache_report"
- // ARP cache report
-
- /////////////////////////////////////////////////////////////////////
-
- /////////////////////////////////////////////////////////////////////
-
- static OSStatus CreateStatusStream(StreamRef *result)
- // Create a raw stream to which we can send the various
- // status reports. We do this by opening the IP driver,
- // and pushing the other modules directly on top of it.
- // This arrangement is just for convenience. We could
- // just have easily opened the null driver and pushed
- // the module of interest on top.
- {
- OSStatus err;
- OSStatus junk;
- StreamRef strm;
-
- // Open up a raw stream to the IP device.
-
- strm = OTStreamOpen(MI_IP_NAME, 0, &err);
- if (err == noErr) {
- // To make this simpler we're going to use sync/blocking mode.
-
- OTStreamSetBlocking(strm);
- OTStreamSetSynchronous(strm);
- }
-
- // Push the various modules of interest on top of the stream.
-
- if (err == noErr) {
- err = OTStreamIoctl(strm, I_PUSH, MI_ARPM_NAME);
- }
- if (err == noErr) {
- err = OTStreamIoctl(strm, I_PUSH, MI_TCPM_NAME);
- }
- if (err == noErr) {
- err = OTStreamIoctl(strm, I_PUSH, MI_UDPM_NAME);
- }
-
- // Clean up and setup result to either be valid or nil.
-
- if (err == noErr) {
- *result = strm;
- } else {
- if (strm != kOTInvalidStreamRef) {
- junk = OTStreamClose(strm);
- OTAssert("CreateStatusStream: OTStreamClose failed", junk == noErr);
- }
- *result = kOTInvalidStreamRef;
- }
- return err;
- }
-
- static void DumpNameDispatchReport(StreamRef strm, char *ndName, char *userVisibleName)
- // Dumps a Name Dispatch (ND) report to standard out. strm
- // is a raw stream that contains the module from which the
- // report is to be extracted. ndName is the Name Dispatch
- // name of the report. userVisibleName is the name of the report
- // in user terminology (only used to make the printout sensible).
- //
- // The general principle is as follows. We send an Name Dispatch ioctl
- // down strm. The relevant module catches the ioctl, creates the
- // report (as text, with null characters as the line terminator)
- // and sends it back to us. The stream head copies the data back
- // into our ioctl buffer.
- //
- // The only tricky thing is to judge the size of the buffer to
- // allocate. We do this in two passes. In the first pass,
- // we create a minimum sized buffer and use it for the ioctl.
- // The ioctl result comes back as the size of the buffer we
- // should have allocated. We then reallocate the buffer
- // and issue the ioctl again. Obviously the size of the report
- // could change between successive ioctls, so we have to
- // loop until it works correctly.
- {
- OSStatus err;
- struct strioctl ndIoctl;
- SInt32 i;
- char *dataBuffer;
- SInt32 dataBufferSize;
- SInt32 minimumDataBufferSize;
- SInt32 ioctlResult;
- Boolean done;
-
- printf("Dumping %s (%s)\n\n", userVisibleName, ndName);
-
- // Allocate a minimum sized buffer for the first ioctl call.
- // It's the length of the string, plus space for the null terminator,
- // plus space for an extra null.
-
- dataBuffer = nil;
- dataBufferSize = OTStrLength(ndName) + 1 + 1;
- minimumDataBufferSize = dataBufferSize;
-
- done = false;
-
- do {
- OTAssert("DumpNameDispatchReport: dataBuffer should have been disposed in the looping case", dataBuffer == nil);
-
- // Allocate the memory according to our current guess as to dataBufferSize.
-
- err = noErr;
- dataBuffer = OTAllocMem( dataBufferSize );
- if (dataBuffer == nil) {
- err = kENOMEMErr;
- }
-
- if (err == noErr) {
-
- // Copy the name of the ND variable we're trying
- // to get into our buffer.
-
- OTStrCopy(dataBuffer, ndName);
-
- // Now put a null after the name in the data buffer.
- // This is because ND requests must be made up
- // of two strings, right after one another in the
- // buffer.
-
- dataBuffer[ OTStrLength(ndName) + 1 ] = 0;
-
- // The ND_GET ioctl returns a value and sets ic_len. A negative
- // value is an error and you can give up now (-: The rule for
- // positive values is a bit weirder. ic_len is always set
- // to the amount of data that is actually returned. If the
- // data available exceeds the available buffer space (as
- // defined by the ic_len on input), the ioctl returns
- // a positive number that is the amount of buffer space
- // needed. So we first call it with a minimal buffer
- // then give it the buffer space it requires. Obviously
- // there's a concurrency race here; we loop until our
- // buffer is big enough.
-
- // First get the size of data buffer we need to allocate.
-
- ndIoctl.ic_cmd = ND_GET;
- ndIoctl.ic_timout = 0;
- ndIoctl.ic_len = dataBufferSize;
- ndIoctl.ic_dp = dataBuffer;
-
- ioctlResult = OTStreamIoctl(strm, I_STR, &ndIoctl);
-
- // printf("••• dataBufferSize = %ld, ic_len = %ld, ioctlResult = %ld\n", dataBufferSize, ndIoctl.ic_len, ioctlResult);
-
- if (ioctlResult < 0) {
- err = ioctlResult;
- } else {
- if (ioctlResult <= dataBufferSize) {
-
- // The report fit into dataBuffer, so let's
- // just print it out and we're done. Remember that
- // the report uses nulls as line terminators, so we
- // have to print it character by character )-:
-
- err = noErr;
- for (i = 0; i < ndIoctl.ic_len; i++) {
- if (dataBuffer[i] == 0) {
- putchar('\n');
- } else {
- putchar(dataBuffer[i]);
- }
- }
- done = true;
- } else {
-
- // The allocated data buffer is the wrong size,
- // so we deallocate and loop.
-
- OTAssert("DumpNameDispatchReport: Should have a data buffer here", dataBuffer != nil);
- OTFreeMem(dataBuffer);
- dataBuffer = nil;
-
- // In this case, the ioctl has returned the size that
- // the buffer /should have been/ to get all the info. We
- // set dataBufferSize to that value and loop.
- //
- // The buffer that we allocate should be able to hold
- // the request (ie the string (with null terminator)
- // and the second null). If the ioctlResult comes
- // back too small, we're going to die when copying
- // the string into the new buffer. However, the ioctlResult
- // should be bigger than the buffer, because otherwise it
- // wouldn't have failed. So we just assert that
- // ioctlResult >= minimumDataBufferSize, just to be sure.
-
- OTAssert("DumpNameDispatchReport: ioctl failed but it should have succeeded", ioctlResult >= minimumDataBufferSize);
-
- dataBufferSize = ioctlResult;
- }
- }
- }
- } while (err == noErr & ! done );
-
- // Clean up.
- if (dataBuffer != nil) {
- OTFreeMem(dataBuffer);
- }
-
- if (err == noErr) {
- printf("Success!\n");
- } else {
- printf("Failed with error %ld.\n", err);
- }
- printf("\n\n");
- }
-
- /////////////////////////////////////////////////////////////////////
-
- void main(void)
- {
- OSStatus err;
- OSStatus junk;
- StreamRef strm;
- InetInterfaceInfo junkInfo;
-
- printf("Hello Cruel World!\n");
- printf("DumpARPCache -- Dumps the Open Transport ARP cache to stdout\n\n");
-
- err = InitOpenTransport();
-
- if (err == noErr) {
-
- err = OTInetGetInterfaceInfo(&junkInfo, kDefaultInetInterface);
- if (err != noErr) {
- printf("This report is not meaningful unless the TCP/IP stack is loaded.\n");
- printf("You can still get the report, it just low on useful content.\n");
- printf("\n");
- err = noErr;
- }
-
- if (err == noErr) {
-
- // Create the raw stream from which we're going to extract
- // report information. This stream contains all the TCP/IP
- // modules ganged together in one convenient package.
-
- err = CreateStatusStream(&strm);
- if (err == noErr) {
-
- // Get and dump each report, one at a time.
-
- DumpNameDispatchReport(strm, ARP_ND_CACHE_REPORT, "ARP Cache");
-
- // Clean up.
-
- junk = OTStreamClose(strm);
- OTAssert("main: OTStreamClose failed", junk == noErr);
- }
- }
-
- CloseOpenTransport();
- }
-
- if (err == noErr) {
- printf("Success.\n");
- } else {
- printf("Failed with error %d.\n", err);
- }
- printf("Done. Press command-Q to Quit.\n");
- }
-